package cn.net.wanji.job;

import cn.net.wanji.config.CommonParamConfig;
import cn.net.wanji.entity.EventCar;
import cn.net.wanji.entity.EventParam;
import cn.net.wanji.entity.VehicleRsuInfo;
import cn.net.wanji.mapper.MonitorMapper;
import cn.net.wanji.utils.StringUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import static cn.net.wanji.config.CommonParamConfig.*;
import static cn.net.wanji.service.iml.DataReceiveServiceImpl.carLicense;
import static cn.net.wanji.utils.TimeUtils.calculateMinutesDifference;


@Slf4j(topic = "定时处理事件列表【ServiceConfigJob】")
@EnableScheduling
@Component
public class RefreshCongestionEventJob {
    private final static Logger extApiLogger = LoggerFactory.getLogger("extApi");
    @Autowired
    private MonitorMapper monitorMapper;

    @Value("${event.retentionTime}")
    private Long retentionTime;
    // 创建格式化器
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Scheduled(fixedRateString = "${event.retentionTime}")
    public void updateEvent() {
        //获取上桥门架数据
        cleanOldData();
        if (CommonParamConfig.cacheUpVehicleRsuInfo.isEmpty()) {
            return;
        }
        if (CommonParamConfig.cacheUpVehicleRsuInfo.size() > 0) {
            extApiLogger.info("CommonParamConfig.cacheUpVehicleRsuInfo: " + CommonParamConfig.cacheUpVehicleRsuInfo.size());
        }

        extApiLogger.info("CommonParamConfig.cacheListPossibleStuckVehicles: " + cacheListPossibleStuckVehicles.size());
        log.info("CommonParamConfig.cacheUpVehicleRsuInfo: " + CommonParamConfig.cacheUpVehicleRsuInfo.size());
        //获取当前时间前半个小时下桥数据


        // 将数据接收处的map复制
        ConcurrentMap<String, JSONObject> cpMap = carLicense;
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 获取当前时间前30分钟的时间
        LocalDateTime sixMinutesBefore = now.minusMinutes(30);
        LocalDateTime twoHoursBefore = now.minusMinutes(60);
        // 格式化当前时间和当前时间前60分钟的时间
        String now_time = now.format(formatter);
        String format_time = sixMinutesBefore.format(formatter);
        // 查询近0.5个小时下桥的数据
        List<VehicleRsuInfo> downVehicleRsuInfos = monitorMapper.selectVehicleInfoDownByTime(now_time, format_time);
        splitCacheIntoDownedAndUndowned(downVehicleRsuInfos);
    }


    // 清理过时的数据
    public static void cleanOldData() {
        LocalDateTime now = LocalDateTime.now();
        // 计算两个时间点之间的 Duration
        if (ObjectUtils.isEmpty(cachenow)) {
            cachenow = now;
        }
        Duration duration = Duration.between(cachenow, now);
        cachenow = now;
        // 获取总秒数
        long secondsBetween = Math.abs(duration.getSeconds());
        LocalDateTime cutoffTime;
        if (secondsBetween > 60) {
            Long a = secondsBetween / 60;
            cutoffTime = now.minusMinutes(CommonParamConfig.UPERIDDATE_TIME_TEN+secondsBetween/60+1);

        }else {
             cutoffTime = now.minusMinutes(CommonParamConfig.UPERIDDATE_TIME_TEN);
        }
        extApiLogger.info("cutoffTime: "+secondsBetween/60+1);

        Iterator<VehicleRsuInfo> iterator = CommonParamConfig.cacheUpVehicleRsuInfo.iterator();
        while (iterator.hasNext()) {
            VehicleRsuInfo vehicleRsuInfo = iterator.next();
            LocalDateTime detectTime = vehicleRsuInfo.getDetectTimeAsLocalDateTime();
            // 如果检测时间早于截止时间，则移除该记录
            if (detectTime.isBefore(cutoffTime)) {
                iterator.remove();
            }
        }
    }

    //切割下桥和在桥数据
    public void splitCacheIntoDownedAndUndowned(List<VehicleRsuInfo> downVehicleRsuInfos) {
        List<VehicleRsuInfo> downederids = new ArrayList<>(); // 已经下桥的数据
        List<VehicleRsuInfo> undownederids = new ArrayList<>(); // 未下桥的数据

        // 遍历上桥数据
        for (VehicleRsuInfo upVehicle : CommonParamConfig.cacheUpVehicleRsuInfo) {
            boolean isDowned = false;

            // 遍历下桥数据
            for (VehicleRsuInfo downVehicle : downVehicleRsuInfos) {
                // 判断是否下桥
                if (!StringUtils.isEmpty(upVehicle.getEtcPassId()) && !StringUtils.isEmpty(downVehicle.getEtcPassId())
                        && upVehicle.getEtcPassId().equals(downVehicle.getEtcPassId())) {
                    LocalDateTime upDateTime = upVehicle.getDetectTimeAsLocalDateTime();
                    LocalDateTime downDateTime = downVehicle.getDetectTimeAsLocalDateTime();
                    if (upDateTime.isAfter(downDateTime)) {
                        extApiLogger.info("上桥通行时间在下桥通行时间后面" + upVehicle.getRecordId()+" "+downVehicle.getRecordId());
                        continue;
                    }
                    // 计算两个时间点之间的 Duration
                    Duration duration = Duration.between(upDateTime, downDateTime);
                    // 获取总秒数
                    long secondsBetween = Math.abs(duration.getSeconds());
                    //上桥预测时间
                    Integer upPredictionTime = 3 * 3600 / upVehicle.getVehicleSpeed();
                    if (upPredictionTime * 2 < secondsBetween) {
                        //滞留数据
                        extApiLogger.info("已经有下桥数据判断滞留" + upVehicle);
                        extApiLogger.info("上桥预测时间： "+upPredictionTime+" 当前时间间隔:"+secondsBetween);

                        insertRetentionEvent(upVehicle,downVehicle.getDetectTime());
                        CommonParamConfig.cacheUpVehicleRsuInfo.remove(upVehicle);
                        cacheListPossibleStuckVehicles.remove(upVehicle);
                    }
                    isDowned = true;
                    break;
                } else if (!StringUtils.isEmpty(upVehicle.getLicenseCode()) && !StringUtils.isEmpty(downVehicle.getLicenseCode()) &&
                        upVehicle.getLicenseCode().equals(downVehicle.getLicenseCode())) {
                    LocalDateTime upDateTime = upVehicle.getDetectTimeAsLocalDateTime();
                    LocalDateTime downDateTime = downVehicle.getDetectTimeAsLocalDateTime();
                    if (upDateTime.isAfter(downDateTime)) {
                        extApiLogger.info("上桥通行时间在下桥通行时间后面" + upVehicle.getRecordId()+" "+downVehicle.getRecordId());
                        continue;
                    }
                    // 计算两个时间点之间的 Duration
                    Duration duration = Duration.between(upDateTime, downDateTime);
                    // 获取总秒数
                    long secondsBetween = Math.abs(duration.getSeconds());
                    //上桥预测时间
                    Integer upPredictionTime = 3 * 3600 / upVehicle.getVehicleSpeed();
                    if (upPredictionTime * 2 < secondsBetween) {
                        //滞留数据
                        extApiLogger.info("已经有下桥数据判断滞留" + upVehicle);
                        extApiLogger.info("上桥预测时间： "+upPredictionTime+" 当前时间间隔:"+secondsBetween);
                        insertRetentionEvent(upVehicle,downVehicle.getDetectTime());
                        CommonParamConfig.cacheUpVehicleRsuInfo.remove(upVehicle);
                        cacheListPossibleStuckVehicles.remove(upVehicle);
                    }
                    isDowned = true;
                    break;

                } else if (!StringUtils.isEmpty(upVehicle.getEtcLicense()) && !StringUtils.isEmpty(downVehicle.getEtcLicense()) &&
                        upVehicle.getEtcLicense().equals(downVehicle.getEtcLicense())) {
                    LocalDateTime upDateTime = upVehicle.getDetectTimeAsLocalDateTime();
                    LocalDateTime downDateTime = downVehicle.getDetectTimeAsLocalDateTime();
                    if (upDateTime.isAfter(downDateTime)) {
                        extApiLogger.info("上桥通行时间在下桥通行时间后面" + upVehicle.getRecordId()+" "+downVehicle.getRecordId());
                        continue;
                    }
                    // 计算两个时间点之间的 Duration
                    Duration duration = Duration.between(upDateTime, downDateTime);
                    // 获取总秒数
                    long secondsBetween = Math.abs(duration.getSeconds());
                    //上桥预测时间
                    Integer upPredictionTime = 3 * 3600 / upVehicle.getVehicleSpeed();
                    if (upPredictionTime * 2 < secondsBetween) {
                        //滞留数据
                        extApiLogger.info("已经有下桥数据判断滞留" + upVehicle);
                        extApiLogger.info("上桥预测时间： "+upPredictionTime+" 当前时间间隔:"+secondsBetween);
                        insertRetentionEvent(upVehicle,downVehicle.getDetectTime());
                        CommonParamConfig.cacheUpVehicleRsuInfo.remove(upVehicle);
                        cacheListPossibleStuckVehicles.remove(upVehicle);
                    }
                    isDowned = true;
                    break;
                }
            }

            if (isDowned) {
                downederids.add(upVehicle);
            } else {
                undownederids.add(upVehicle);
            }
        }
//求已经下桥的车平均通过桥的时间
        double averageCrossingTime = 0;
        if (downederids.size() > 0) {
            averageCrossingTime = calculateAverageCrossingTime(downederids);
        } else {
            averageCrossingTime = calculateAverageCrossingTime(undownederids);
        }

        // 输出结果或者进行其他处理
        extApiLogger.info("已经下桥的数据数量: " + downederids.size());
        extApiLogger.info("未下桥的数据数量: " + undownederids.size());
        extApiLogger.info("所有车辆通过桥的平均时间 (秒): : " + averageCrossingTime);
        addIfNotExists(undownederids);
        addIfExistsUperid(downederids);

        // 根据未下桥集合计算可能的滞留车辆
        List<VehicleRsuInfo> possibleStuckVehicles = findPossibleStuckVehicles(cacheListPossibleStuckVehicles, averageCrossingTime);
        extApiLogger.info("possibleStuckVehicles: " + possibleStuckVehicles.size());
        extApiLogger.info("cacheListPossibleStuckVehicles: " + cacheListPossibleStuckVehicles.size());
        extApiLogger.info("cacheUpVehicleRsuInfo: " + cacheUpVehicleRsuInfo.size());
        for (int i = 0; i < possibleStuckVehicles.size(); i++) {
            if (i < 10) {
                extApiLogger.info(possibleStuckVehicles.get(i).getRecordId() + ": " + possibleStuckVehicles.get(i).getLicenseCode() + ": " + possibleStuckVehicles.get(i).getErId());
//                System.out.println(possibleStuckVehicles.get(i).getRecordId() + ": " + possibleStuckVehicles.get(i).getLicenseCode() + ": " + possibleStuckVehicles.get(i).getErId());
            }
        }
        // 如果需要返回结果
        // return new Pair<>(downederids, undownederids);
    }

    /**
     * 计算所有车辆通过桥的平均时间。
     *
     * @param vehicles 已经下桥的车辆列表
     * @return 平均过桥时间 (秒)
     */
    private double calculateAverageCrossingTime(List<VehicleRsuInfo> vehicles) {
        double totalCrossingTime = 0.0;
        int count = 0;

        // 桥长 (单位: 米)
        final double bridgeLength = 3000.0; // 3 km

        for (VehicleRsuInfo vehicle : vehicles) {
            double speed = ObjectUtils.isEmpty(vehicle) ? 0 : vehicle.getVehicleSpeed();// 单位: km/h
            if (speed == 0) {
                continue; // 避免除以零
            }

            // 将速度从 km/h 转换为 m/s
            double speedInMetersPerSecond = speed * 1000 / 3600;

            // 计算单个车辆的过桥时间 (秒)
            double crossingTime = bridgeLength / speedInMetersPerSecond;

            totalCrossingTime += crossingTime;
            count++;
        }

        if (count == 0) {
            return 0.0; // 如果没有车辆，则返回 0
        }

        return totalCrossingTime / count;
    }

    /**
     * 根据未下桥集合中的车辆速度和桥长计算可能的滞留车辆。
     *
     * @param vehicles    未下桥的车辆列表
     * @param averageTime 所有车辆通过桥的平均时间
     * @return 可能的滞留车辆列表
     */
    private List<VehicleRsuInfo> findPossibleStuckVehicles(ConcurrentLinkedQueue<VehicleRsuInfo> vehicles, double averageTime) {
        List<VehicleRsuInfo> possibleStuckVehicles = new ArrayList<>();

        // 桥长 (单位: 米)
        final double bridgeLength = 3000.0; // 3 km

        for (VehicleRsuInfo vehicle : vehicles) {
            double speed = ObjectUtils.isEmpty(vehicle) ? 0 : vehicle.getVehicleSpeed(); // 单位: km/h
            if (speed == 0) {
                continue; // 避免除以零
            }
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime detectTimeAsLocalDateTime = vehicle.getDetectTimeAsLocalDateTime();
            // 计算两个时间点之间的 Duration
            Duration duration = Duration.between(now, detectTimeAsLocalDateTime);
            // 获取总秒数
            long secondsBetween = Math.abs(duration.getSeconds());
            // 将速度从 km/h 转换为 m/s
            double speedInMetersPerSecond = speed * 1000 / 3600;

            // 计算单个车辆的过桥时间 (秒)
            double crossingTime = bridgeLength / speedInMetersPerSecond;

            // 如果 T 大于（平均过桥时间+预测时间）/2的两倍 ，则认为可能为滞留车辆
            if (crossingTime+averageTime <  secondsBetween) {
                //新增滞留
                extApiLogger.info("新增滞留未下桥的上桥车辆： "+vehicle);
                extApiLogger.info("预测时间： "+crossingTime+" 平均值时间： "+averageTime+" 当前时间间隔:"+secondsBetween);
                insertRetentionEvent(vehicle,"");
//                cacheListPossibleStuckVehicles.remove(vehicle);
//                cacheUpVehicleRsuInfo.remove(vehicle);
                vehicle.setUpEridCrossingTime(crossingTime + averageTime);
                possibleStuckVehicles.add(vehicle);
            }
        }

        return possibleStuckVehicles;
    }

    //添加疑似滞留数据到缓存里
    public List<String> addIfNotExists(List<VehicleRsuInfo> possibleStuckVehicles) {
        List<String> addedRecordIds = new ArrayList<>();

        if (possibleStuckVehicles == null || possibleStuckVehicles.isEmpty()) {
            return addedRecordIds; // 如果列表为空或为null，则直接返回空列表
        }

        for (VehicleRsuInfo vehicleRsuInfo : possibleStuckVehicles) {
            String recordId = vehicleRsuInfo.getRecordId();

            // Check if the recordId exists in the cache list
            boolean exists = cacheListPossibleStuckVehicles.stream()
                    .anyMatch(v -> v.getRecordId().equals(recordId));

            // If not, add the VehicleRsuInfo object to the cache list and collect the recordId
            if (!exists) {
                cacheListPossibleStuckVehicles.add(vehicleRsuInfo);
                addedRecordIds.add(recordId);
            }
        }

        return addedRecordIds;
    }
    //如果未上桥数据缓存存在上桥数据就删除
    public void addIfExistsUperid(List<VehicleRsuInfo> uperidVehicles) {

        if (uperidVehicles == null || uperidVehicles.isEmpty()) {
            return; // 如果列表为空或为null，则直接返回空列表
        }

        for (VehicleRsuInfo vehicleRsuInfo : uperidVehicles) {
            String recordId = vehicleRsuInfo.getRecordId();

            // Check if the recordId exists in the cache list
            boolean exists = cacheListPossibleStuckVehicles.stream()
                    .anyMatch(v -> v.getRecordId().equals(recordId));

            // If not, add the VehicleRsuInfo object to the cache list and collect the recordId
            if (exists) {
                cacheListPossibleStuckVehicles.remove(vehicleRsuInfo);
                extApiLogger.info("删除缓存里上桥数据"+vehicleRsuInfo.getRecordId());
            }
        }
    }
    //新增滞留数据
    public void insertRetentionEvent(VehicleRsuInfo vehicleRsuInfo,String downDetectTime){
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 格式化当前时间和当前时间前30分钟的时间
        String now_time = now.format(formatter);
        EventCar eventCar = new EventCar();
        eventCar.setEventNumber(1);
        eventCar.setRecordCarId(vehicleRsuInfo.getRecordId() + vehicleRsuInfo.getCarId() + "3");
        eventCar.setRecordId(vehicleRsuInfo.getRecordId());
        eventCar.setErId(vehicleRsuInfo.getErId());
        eventCar.setEventType("3");
        eventCar.setCarId(vehicleRsuInfo.getCarId());
        eventCar.setTime(now_time);
        eventCar.setDetectTime(vehicleRsuInfo.getDetectTime());
        eventCar.setGantryTime(vehicleRsuInfo.getDetectTime());
        eventCar.setPlate(vehicleRsuInfo.getLicenseCode());
        eventCar.setUpBridgeTime(vehicleRsuInfo.getDetectTime());
        if (!StringUtils.isEmpty(downDetectTime)) {
            eventCar.setDownBridgeTime(downDetectTime);
        }
        eventCar.setSpeed(String.valueOf(vehicleRsuInfo.getVehicleSpeed()));
        eventCar.setType(String.valueOf(vehicleRsuInfo.getIdentifyType()));
        eventCar.setHeadPic(vehicleRsuInfo.getHeadImage());
        eventCar.setSidePic(vehicleRsuInfo.getSideImage());
        eventCar.setVideo(vehicleRsuInfo.getVideo());
        List<EventCar> eventCars = monitorMapper.selectEventInfoByCarId(vehicleRsuInfo.getCarId());
        if (eventCars.isEmpty()) {
            extApiLogger.info("新增滞留事件"+vehicleRsuInfo.getRecordId());
            monitorMapper.insertEvent(eventCar);
        }else{
            if (!StringUtils.isEmpty(downDetectTime)) {
                extApiLogger.info("更新滞留事件1: "+vehicleRsuInfo.getRecordId()+" "+vehicleRsuInfo.getCarId());
                for (EventCar car : eventCars) {
                    if (StringUtils.isEmpty(car.getDownBridgeTime())) {
                        car.setDownBridgeTime(downDetectTime);
                        extApiLogger.info("更新滞留事件: "+vehicleRsuInfo.getRecordId()+" "+vehicleRsuInfo.getCarId());
                        monitorMapper.updateEventInfoByCarId(car);
                    }
                }
            }
        }
    }
    public static void main(String[] args) {
        VehicleRsuInfo vehicleRsuInfo = new VehicleRsuInfo();
        vehicleRsuInfo.setDetectTime("2024-08-02 11:28:46");
//        vehicleRsuInfo.setDetectTime("2024-07-26 15:44:28");
//        vehicleRsuInfo.setRecordId("1");
//        CommonParamConfig.cacheUpVehicleRsuInfo.add(vehicleRsuInfo);
//        System.out.println("------------"+CommonParamConfig.cacheUpVehicleRsuInfo.toString());
//        cleanOldData();
        LocalDateTime now = LocalDateTime.now();
        Duration duration = Duration.between(LocalDateTime.parse("2024-08-02 11:33:44", CommonParamConfig.LOCAL_DATE_TIME), vehicleRsuInfo.getDetectTimeAsLocalDateTime());
        // 获取总秒数
        long secondsBetween = Math.abs(duration.getSeconds());
        System.out.println("------------" + secondsBetween
        );
    }

}
